package c2

import (
	"errors"
	"log"
	"strings"

	"gitee.com/tuboyou/c2/request"
	"gitee.com/tuboyou/c2/u2"
)

// MultipartRequest 表示一个multipart/form-data格式的HTTP请求
// 字段说明：
//
//	Name - 请求名称
//	Host - 请求主机地址
//	Path - 请求路径
//	Params - 请求参数
//	Headers - 请求头
//	Files - 要上传的文件
//	Body - 请求体
//	Meta - 元数据，用于存储一些附加信息
//	Timeout - 请求超时时间，单位为毫秒
//	Error - 错误信息
//	Retry - 重试次数
type MultipartRequest struct {
	Name    string            `json:"name"`
	Host    string            `json:"host"`
	Path    string            `json:"path"`
	Params  map[string]string `json:"param"`
	Headers map[string]string `json:"headers"`
	Files   map[string]string `json:"files"`
	Body    map[string]string `json:"body"`
	Meta    map[string]string `json:"meta"`    //元数据，用于存储一些信息
	Timeout int               `json:"timeout"` //单位：毫秒
	Error   error             `json:"error"`   //错误信息
	Retry   int               `json:"retry" default:"0"`
}

// PostMultipart 创建一个新的multipart/form-data格式的POST请求
//
// 参数：
//
//	name - 请求名称
//	host - 请求主机
//	path - 请求路径
//
// 返回值：
//
//	*MultipartRequest - 新创建的MultipartRequest对象
//
// 注意：
//
//  1. 默认会添加xfrom请求头
//  2. 默认超时时间为5000毫秒
//  3. 支持文件上传
func PostMultipart(name, host, path string) *MultipartRequest {
	return &MultipartRequest{Name: name, Host: host, Path: path, Params: make(map[string]string), Headers: map[string]string{"xfrom": iconf.xfrom}, Files: make(map[string]string), Body: make(map[string]string), Meta: make(map[string]string), Timeout: 5000}
}

// SetParam 设置multipart请求参数
//
// 参数：
//
//	Name - 参数名称
//	Value - 参数值
//
// 注意：
//
//  1. 如果启用了调试模式，会打印设置日志
func (t *MultipartRequest) SetParam(Name, Value string) {
	t.Params[Name] = Value
	if iconf.showDebug {
		log.Println("设置参数：", Name, ",值：", Value)
	}
}

// SetHeader 设置multipart请求头
//
// 参数：
//
//	Name - 头名称
//	Value - 头值
//
// 注意：
//
//  1. 如果启用了调试模式，会打印设置日志
func (t *MultipartRequest) SetHeader(Name, Value string) {
	t.Headers[Name] = Value
	if iconf.showDebug {
		log.Println("设置header：", Name, ",值：", Value)
	}
}

// SetMeta 设置multipart元数据
//
// 参数：
//
//	Name - 元数据名称
//	Value - 元数据值
//
// 注意：
//
//  1. 如果启用了调试模式，会打印设置日志
func (t *MultipartRequest) SetMeta(Name, Value string) {
	t.Meta[Name] = Value
	if iconf.showDebug {
		log.Println("设置meta：", Name, ",值：", Value)
	}
}

// SetBody 设置multipart请求体
//
// 参数：
//
//	Name - 字段名称
//	Value - 字段值
//
// 注意：
//
//  1. 如果启用了调试模式，会打印设置日志
func (t *MultipartRequest) SetBody(Name, Value string) {
	t.Body[Name] = Value
	if iconf.showDebug {
		log.Println("设置body：", Name, ",值：", Value)
	}
}

// SetFile 设置multipart要上传的文件
//
// 参数：
//
//	Name - 字段名称
//	Value - 文件路径
//
// 注意：
//
//  1. 如果文件不存在会返回错误
//  2. 会自动去除路径中的多余引号
//  3. 如果启用了调试模式，会打印设置日志
func (t *MultipartRequest) SetFile(Name, Value string) {
	if t.Error != nil {
		return
	}
	Value = strings.TrimSuffix(Value, "\"")
	Value = strings.TrimSuffix(Value, "“")
	if !u2.ExistFile(Value) {
		t.Error = errors.New("文件不存在：" + Value)
		if iconf.showDebug {
			log.Println("设置文件出现异常：", t.Error)
		}
		return
	}
	t.Files[Name] = Value
	if iconf.showDebug {
		log.Println("设置文件：", Name, ",值：", Value)
	}
}

// SetTimeout 设置multipart请求超时时间
//
// 参数：
//
//	timeout - 超时时间，单位为毫秒
//
// 注意：
//
//  1. 如果启用了调试模式，会打印设置日志
func (t *MultipartRequest) SetTimeout(timeout int) {
	t.Timeout = timeout
	if iconf.showDebug {
		log.Println("设置超时时间（毫秒）：", timeout)
	}
}

// SetRetry 设置multipart请求重试次数
//
// 参数：
//
//	r - 重试次数
//
// 注意：
//
//  1. 如果启用了调试模式，会打印设置日志
func (t *MultipartRequest) SetRetry(r int) {
	t.Retry = r
	if iconf.showDebug {
		log.Println("设置重试次数：", r)
	}
}

// String 获取multipart请求的字符串表示
//
// 返回值：
//
//	string - 请求的JSON格式字符串
func (t *MultipartRequest) String() string {
	return u2.I2S(t)
}

// Run 执行multipart/form-data格式的HTTP请求
//
// 返回值：
//
//	Response - 包含响应结果的结构体
//
// 注意：
//
//  1. 会自动处理重试逻辑
//  2. 会将结果保存到指定路径（如果设置了结果保存路径）
//  3. 会合并全局请求头
//  4. 如果启用了调试模式，会打印请求和重试日志
func (t *MultipartRequest) Run() Response {
	query := make(map[string]string)
	for k, v := range t.Params {
		query[k] = v
	}
	tmpHeaders := make(map[string]string)
	for k, v := range iconf.globalHeaders {
		tmpHeaders[k] = v
	}

	for k, v := range t.Headers {
		tmpHeaders[k] = v
	}
	inner_retry := t.Retry
	if inner_retry == 0 {
		inner_retry = iconf.retry
	}
	var res Response
	for i := -1; i < inner_retry; i++ {
		inner_res := request.PostMultipart(t.Name, t.Host+t.Path, query, t.Body, t.Files, tmpHeaders, t.Timeout, t.Error)
		res = Response(inner_res)
		res.Result2File(iconf.resultPath, true, false)
		if res.Error == nil {
			break
		} else {
			if iconf.showDebug {
				if i == -1 {
					log.Print("请求异常：", inner_res.Req.Url.String(), ",错误信息：\n", inner_res.Req.GetError())
					if inner_retry > 0 {
						log.Println(",正在重试")
					}
				} else {
					log.Println("请求异常[重试]：", inner_res.Req.Url.String(), ",错误信息：\n", res.Error, ",重试：", i+1, "/", inner_retry)
				}
			}
		}
	}
	return res
}
